package com.enjoyor.soa.traffic.util.helper;

import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Pattern;


import com.enjoyor.soa.traffic.util.base.BaseDataFormat;
import com.enjoyor.soa.traffic.util.exception.ParameterException;

/**
 * @author Administrator
 *
 */
public class MapHelper {

	/**
	 * 将实体类转换成map型
	 * @param obj
	 * @return
	 */
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public synchronized static Map reflectPojo(Object obj) {
		Map hashMap = new HashMap();
		try {
			Class c = obj.getClass();
			Field[] fields = c.getDeclaredFields();
			for (Field field : fields) {
				PropertyDescriptor pd = new PropertyDescriptor(field.getName(), c);
				Method getMethod = pd.getReadMethod();
				Object o = getMethod.invoke(obj);
				hashMap.put(field.getName(), o);
			}
		} catch (Throwable e) {
			System.err.println(e);
		}
		return hashMap;
	}

	/**
	 * 两个不同类型相同属性的Object拷贝。通过getter、setter方法拷贝属性<br />
	 * 调用所有相对应的source的getter和target的setter：<br />
	 * &nbsp;&nbsp;&nbsp;1.名称相对应(getXXX、setXXX)<br />
	 * &nbsp;&nbsp;&nbsp;2.类型对应(setter只有一个参数，getter无参数，
	 * getter返回类型为setter参数类型或其子类)
	 * @param source
	 * @param target
	 * @param copyNull 默认false,source的getter返回值为null,则不调用target对应的setter
	 * @return target
	 * @deprecated 弃用，请使用 {@link org.springframework.beans.BeanUtils#copyProperties(Object source, Object target)}.
	 */
	public static <T> T copyBean(Object source, T target) {
		return copyBean(source, target, false);
	}
	/**
	 * @deprecated 弃用，请使用 {@link org.springframework.beans.BeanUtils#copyProperties(Object source, Object target)}.
	 */
	public static <T> T copyBean(Object source, T target, boolean copyNull) {
		if (source == null || target == null)
			return target;
		Class<?> tarCl = target.getClass();
		Class<?> souCl = source.getClass();
		Method[] tarMethod = tarCl.getMethods();
		Method[] souMethod = souCl.getMethods();
		String gs = "get(\\w+)";
		Pattern getM = Pattern.compile(gs);
		String ss = "set(\\w+)";
		Pattern setM = Pattern.compile(ss);
		String rapl = "$1";

		for (Method tarmet : tarMethod) {
			if (!tarmet.getDeclaringClass().equals(Object.class) && Pattern.matches(ss, tarmet.getName())) {
				String tarparam = setM.matcher(tarmet.getName()).replaceAll(rapl);
				for (Method soumet : souMethod) {
					try {
						if (!soumet.getDeclaringClass().equals(Object.class) && Pattern.matches(gs, soumet.getName())) {
							String souparam = getM.matcher(soumet.getName()).replaceAll(rapl);
							Class<?>[] par = tarmet.getParameterTypes();
							if (souparam != null && souparam.equals(tarparam) && soumet.getParameterTypes().length == 0 && tarmet.getParameterTypes().length == 1 && par[0].isAssignableFrom(soumet.getReturnType())) {
								Object sour = soumet.invoke(source);
								if (copyNull || sour != null)
									tarmet.invoke(target, sour);
								break;
							}
						}
					} catch (Throwable e) {
					}
				}
			}
		}
		return target;
	}

	/**
	 * 两个不同类型，相互比较，通过getter方法比较属性。<br/>
	 * 比较a,b所有相同的getter（getter名称相同、无参数、返回类型相同）的返回值。
	 */
	public static boolean isequal(Object a, Object b) {
		if (a == null && a == null)
			return true;
		if (a != null && a != null) {
			Class<?> aCl = a.getClass();
			Class<?> bCl = b.getClass();
			Method[] aMethod = aCl.getMethods();
			Method[] bMethod = bCl.getMethods();
			String gs = "get(\\w+)";
			Pattern.compile(gs);

			for (Method amet : aMethod) {
				if (!amet.getDeclaringClass().equals(Object.class) && Pattern.matches(gs, amet.getName())) {
					for (Method bmet : bMethod) {
						try {
							if (!bmet.getDeclaringClass().equals(Object.class) && Pattern.matches(gs, bmet.getName())) {
								if (amet.getName().equals(bmet.getName()) && amet.getReturnType() != null && amet.getReturnType().equals(bmet.getReturnType()) && amet.getParameterTypes().length == 0 && bmet.getParameterTypes().length == 0) {
									Object aret = amet.invoke(a);
									Object bret = bmet.invoke(b);
									if ((aret == null && bret != null) || (aret != null && !aret.equals(bret))) {
										return false;
									}
									break;
								}
							}
						} catch (Throwable e) {
						}
					}
				}
			}
			return true;
		}
		return false;
	}

	/**
	 * 将bean转换为map
	 * @param bean
	 * @return
	 */
	public static Map<String, Object> bean2Map(Object bean) {
		Map<String, Object> map = new HashMap<String, Object>();
		try {
			Class<?> beanType = bean.getClass();
			for (Field field : beanType.getDeclaredFields()) {
				String fieldName = field.getName();
				for (Method met : beanType.getMethods()) {
					try {
						if ((Pattern.matches("get(\\w+)", met.getName())||Pattern.matches("is(\\w+)", met.getName())) && met.getParameterTypes().length == 0 && met.getDeclaringClass() != Object.class) {
							Pattern pattern = Pattern.matches("get(\\w+)", met.getName())?Pattern.compile("get(\\w+)"):Pattern.compile("is(\\w+)");
							String param = pattern.matcher(met.getName()).replaceAll("$1");
							if (fieldName.equalsIgnoreCase(param)) {
								Object ret = met.invoke(bean);
								if (ret != null) {
									map.put(fieldName, ret);
								}
								break;
							}
						}
					} catch (Throwable ex) {
					}
				}
			}
		} catch (Throwable e) {
		}
		return map;
	}

	/**
	 * 将map转换为bean
	 * @param map
	 * @param beanType
	 * @return
	 */
	public static <T> T map2Bean(Map<String, Object> map, Class<T> beanType) {
		T bean = null;
		try {
			bean = beanType.newInstance();
			for (Field field : beanType.getDeclaredFields()) {
				try {
					String fieldName = field.getName();
					if (map.get(fieldName) != null) {
						field.setAccessible(true);
						if(map.get(fieldName).getClass().equals(String.class) && !field.getType().equals(String.class)){
							field.set(bean, BaseDataFormat.castTo(map.get(fieldName).toString(), field.getType()));
						}else{
							if(map.get(fieldName).getClass().equals(field.getType())){
								field.set(bean, map.get(fieldName));
							}else{
								field.set(bean, MapHelper.map2Bean(MapHelper.bean2Map(map.get(fieldName)), field.getType()));
							}
						}
					}
				} catch (Throwable ex) {
				}
			}
		} catch (Throwable e) {
		}
		return bean;
	} 
	/**
	 * 字符串转bean
	 * @param str
	 * @param beanType
	 * @return
	 * @throws Exception
	 */
	public static <T> T Str2Bean(String str, Class<T> beanType) throws Exception
	{
		Map<String, Object> map = JsonHelper.jsonStrToMap(str);
		return map2Bean(map, beanType);
	}
	/**
	 * bean转map，再由map转bean（多用于dto和pojo之间的互转）
	 * @param source
	 * @param target
	 * @return
	 */
	public static Object beanToBean(Object source, Object target) {
		try {
			Map<String, Object> map = MapHelper.bean2Map(source);
			target = MapHelper.map2Bean(map, target.getClass());
		} catch (Throwable ex) {
		}
		return target;
	}
	/**
	 * list转list（多用于dto和pojo列表的相互转换）
	 * @param list
	 * @param sourceClass
	 * @param targetClass
	 * @return
	 */
	@SuppressWarnings("all") 	
	public static <T> List<T> lstToList(List list, Class sourceClass,
			Class<T> targetClass) {
		List<T> targetList = new ArrayList<T>();
		if (null != list) {
			for (int i = 0; i < list.size(); i++) {
				T target;
				try {
					target = (T) targetClass.newInstance();
					Object source = list.get(i);
					target = (T) MapHelper.beanToBean(source, target);
					if (null != target)
						targetList.add(target);
				} catch (InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} catch (IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return targetList;
	}
	
	/**
	 * 把一个方法中的参数都放到一个map中
	 * @param method
	 * @param values 方法中的参数值
	 * @return map
	 * @throws Exception 
	 */
	public static Map<String, Object> getMethodParam(Method method,Object...values) throws ParameterException{
		Map<String, Object> map = new HashMap<String, Object>();

		Parameter[] parameters=method.getParameters();
		if(parameters.length!=values.length) {
			throw new ParameterException("参数不完整");
		}
		for(int i=0;i<parameters.length;i++) {
			map.put(parameters[i].getName(), values[i]);
		}
		return map;
	}
}
